﻿using System;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using ServeAnything.Service;

namespace ServeAnything
{
    public static class ServiceDelegateInstaller
    {
        private const string ProductName = "ServeAnything";
        private const string DelegateServiceFilename = "DelegateService.exe";
        private const string DelegateServiceConfigFilename = "DelegateService.exe.config";

        public static Task InstallAsync(string serviceName, string servicePath, string arguments, string username, string password)
        {
            return Task.Run(() => Install(serviceName, servicePath, arguments, username, password));
        }

        private static void Install(string serviceName, string servicePath, string arguments, string username, string password)
        {
            var assembly = Assembly.GetExecutingAssembly();
            string delegateServiceResourceName = string.Format("{0}.{1}", ProductName, DelegateServiceFilename);
            string delegateServiceConfigResourceName = string.Format("{0}.{1}", ProductName, DelegateServiceConfigFilename);

            var installFolder = GetInstallFolder(serviceName);

            if (!Directory.Exists(installFolder))
                Directory.CreateDirectory(installFolder);

            var delegateServicePath = Path.Combine(installFolder, DelegateServiceFilename);
            using (var resourceStream = assembly.GetManifestResourceStream(delegateServiceResourceName))
            {
                if (resourceStream == null)
                    throw new InvalidOperationException("Resource not found.");

                using (var installStream = new FileStream(delegateServicePath, FileMode.Create, FileAccess.Write))
                    resourceStream.CopyTo(installStream);
            }

            using (var resourceStream = assembly.GetManifestResourceStream(delegateServiceConfigResourceName))
            {
                if (resourceStream == null)
                    throw new InvalidOperationException("Resource not found.");

                var delegateServiceConfigPath = Path.Combine(installFolder, DelegateServiceConfigFilename);
                using (var installStream = new FileStream(delegateServiceConfigPath, FileMode.Create, FileAccess.Write))
                    resourceStream.CopyTo(installStream);
            }

            var config = ConfigurationManager.OpenExeConfiguration(delegateServicePath);
            var settings = config.AppSettings.Settings;
            settings["Path"].Value = servicePath;
            settings["Arguments"].Value = arguments;
            config.Save(ConfigurationSaveMode.Modified);

            var displayName = string.Format("{0} Surrogate", serviceName);
            ServiceInstaller.InstallAndStart(serviceName, displayName, delegateServicePath, username, password);
        }

        public static Task UninstallAsync(string serviceName)
        {
            return Task.Run(() => Uninstall(serviceName));
        }

        private static void Uninstall(string serviceName)
        {
            ServiceInstaller.StopService(serviceName);
            ServiceInstaller.Uninstall(serviceName);

            var installFolder = GetInstallFolder(serviceName);

            if (Directory.Exists(installFolder))
                Directory.Delete(installFolder, true);
        }

        private static string GetInstallFolder(string serviceName)
        {
            var appDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            var installerFolder = Path.Combine(appDataFolder, ProductName);
            return Path.Combine(installerFolder, serviceName);
        }
    }
}
